﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using PropertyManagment.common.lang;
using PropertyManagment.common.utils;
using PropertyManagment.config.cache;
using PropertyManagment.config.jwt;
using PropertyManagment.entity;
using PropertyManagment.service;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace PropertyManagment.controllers {

    /// <summary>
    /// 授权控制器
    /// </summary>
    public class AuthController : Controller {

        public ILogger<AuthController> logger { get; set; }
        public ICacheHelper cache { get; set; }
        public IConfiguration configuration { get; set; }
        public SysUserService sysUserService { get; set; }

        [HttpGet]
        [AllowAnonymous]
        public IActionResult GetToken() {
            try {
                var jwtConfig = configuration.GetSection("JwtConfig").Get<JwtConfig>();

                //定义发行人issuer
                //string iss = "JWTBearer.Auth";
                //string iss = configuration["Jwt:Issuer"];
                string iss = jwtConfig.issuer;
                //定义受众人audience
                //string aud = "api.auth";
                string aud = jwtConfig.audience;

                //定义许多种的声明Claim,信息存储部分,Claims的实体一般包含用户和一些元数据
                IEnumerable<Claim> claims = new Claim[]{
                    new Claim("Id","1"),
                    new Claim(ClaimTypes.Name,"admin"),
                    //new Claim("Roles","admin"),
                    //new Claim(ClaimTypes.Role, "admin")
                };
                claims = claims.Append<Claim>(new Claim(ClaimTypes.Role, "admin"));

                //notBefore  生效时间
                // long nbf =new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds();
                var nbf = DateTime.UtcNow;
                //expires   //过期时间
                // long Exp = new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds();
                var Exp = DateTime.UtcNow.AddSeconds(Convert.ToDouble(jwtConfig.expires));
                //signingCredentials  签名凭证
                //string sign = "q2xiARx$4x3TKqBJ"; //SecurityKey 的长度必须 大于等于 16个字符
                string sign = jwtConfig.signingKey;
                var secret = Encoding.UTF8.GetBytes(sign);
                var key = new SymmetricSecurityKey(secret);
                var signcreds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                var jwt = new JwtSecurityToken(issuer: iss, audience: aud, claims: claims, notBefore: nbf, expires: Exp, signingCredentials: signcreds);
                var JwtHander = new JwtSecurityTokenHandler();
                var token = JwtHander.WriteToken(jwt);
                return Ok(new {
                    access_token = token,
                    token_type = "Bearer",
                });
            } catch (Exception ex) {
                throw;
            }
        }


        /// <summary>
        /// 获取验证码图片
        /// </summary>
        /// <response code="200">返回验证码图片</response>
        /// <returns></returns>
        [HttpGet]
        [Route("/captcha")]
        [AllowAnonymous]
        public Result captcha() {

            Producer producer = new Producer();

            string key = Guid.NewGuid().ToString();
            string code = producer.createText();

            // 为了测试
            //string key = "aaaaa";
            //string code = "11111";

            Bitmap bitmap = producer.createImage(code);
            string base64Img = "data:image/jpeg;base64," + producer.ToBitmapBase64(bitmap);

            // 存储到redis中
            cache.Set(key, code, 120);
            logger.LogInformation("验证码 -- {} - {}", key, code);

            return Result.succ(new Dictionary<string, string> {
                ["captchaImg"] = base64Img,
                ["token"] = key
            });
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <response code="200">返回用户信息</response>
        /// <returns></returns>
        [HttpGet]
        [Route("/sys/userInfo")]
        [Authorize]
        public Result userInfo() {
            SysUser sysUser = sysUserService.getByUsername(HttpContext.User.Identity.Name);

            return Result.succ(new Dictionary<string, string> {
                ["id"] = sysUser.id.ToString(),
                ["username"] = sysUser.username,
                ["avatar"] = sysUser.avatar,
                ["created"] = sysUser.created.ToString("yyyy-MM-dd HH:mm:ss")
            });
        }

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        /// <param name="code">验证码</param>
        /// <param name="key">验证码token</param>
        /// <response code="200">验证通过返回用户token</response>
        /// <returns></returns>
        [HttpPost]
        [Route("/login")]
        [AllowAnonymous]
        public Result login(string username, string password, string code, string key) {

            //Debug.WriteLine(username);
            //Debug.WriteLine(password);
            //Debug.WriteLine(code);
            //Debug.WriteLine(key);

            if (code.IsNullOrEmpty() || key.IsNullOrEmpty()) {
                return Result.fail("请输入验证码");
            } else {
                string cpCode = cache.Get<string>(key);

                if (code == cpCode) {
                    if (username.IsNullOrEmpty() || password.IsNullOrEmpty()) {
                        return Result.fail("请输入用户名或者密码");
                    } else {
                        password = Producer.Encrypt(password);
                        var user = sysUserService.loadUserByUsername(username, password);
                        if (user != null) {
                            //string token = getToken(username, user.authorities);
                            var jwtConfig = configuration.GetSection("JwtConfig").Get<JwtConfig>();
                            string token = JwtToken.getToken(jwtConfig, username, user.authorities);
                            //把token存进缓存，过期时间为token的4倍
                            cache.Set("Bearer " + token, username, jwtConfig.expires * 4);
                            //string ss = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsiUk9MRV9ub3JtYWwiLCJST0xFX2FkbWluIiwiUk9MRV9tYW5hZ2UiLCJzeXM6bWFuYWdlIiwic3lzOnVzZXI6bGlzdCIsInN5czpyb2xlOmxpc3QiLCJzeXM6bWVudTpsaXN0Iiwic3lzOnRvb2xzIiwic3lzOmRpY3Q6bGlzdCIsInN5czpyb2xlOnNhdmUiLCJzeXM6dXNlcjpzYXZlIiwic3lzOnVzZXI6dXBkYXRlIiwic3lzOnVzZXI6ZGVsZXRlIiwic3lzOnVzZXI6cm9sZSIsInN5czp1c2VyOnJlcGFzcyIsInN5czpyb2xlOnVwZGF0ZSIsInN5czpyb2xlOmRlbGV0ZSIsInN5czpyb2xlOnBlcm0iLCJzeXM6bWVudTpzYXZlIiwic3lzOm1lbnU6dXBkYXRlIiwic3lzOm1lbnU6ZGVsZXRlIiwic3lzOnRlc3Q6bGlzdCIsInN5czp0ZXN0MyJdLCJuYmYiOjE2NzU1MDAwMjUsImV4cCI6MTY3NTUwMDA2MSwiaXNzIjoiSldUQmVhcmVyLkF1dGgiLCJhdWQiOiJhcGkuYXV0aCJ9.gF-P6aNZS8t2ZGJVhmYI8oImz-zSBc3YO9-1r1jibh0";
                            //cache.Set(ss, username, jwtConfig.expires * 200);
                            //Debug.WriteLine("保存的token");
                            //Debug.WriteLine("Bearer " + token);

                            return Result.succ(new Dictionary<string, string> {
                                ["access_token"] = token,
                                ["token_type"] = "Bearer"
                            });
                        } else {
                            return Result.fail("用户名或者密码错误");
                        }
                    }
                } else {
                    return Result.fail("验证码错误");
                }
            }
            
        }

        private string getToken(string username, List<string> roles) {
            var jwtConfig = configuration.GetSection("JwtConfig").Get<JwtConfig>();

            //定义发行人issuer
            //string iss = "JWTBearer.Auth";
            //string iss = configuration["Jwt:Issuer"];
            string iss = jwtConfig.issuer;
            //定义受众人audience
            //string aud = "api.auth";
            string aud = jwtConfig.audience;

            //定义许多种的声明Claim,信息存储部分,Claims的实体一般包含用户和一些元数据
            IEnumerable<Claim> claims = new Claim[]{
                new Claim(ClaimTypes.Name, username)
            };

            //添加用户权限
            foreach (var role in roles) {
                claims = claims.Append(new Claim(ClaimTypes.Role, role));
            }

            //notBefore  生效时间
            // long nbf =new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds();
            var nbf = DateTime.UtcNow;
            //expires   //过期时间
            // long Exp = new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds();
            var exp = DateTime.UtcNow.AddSeconds(Convert.ToDouble(jwtConfig.expires));
            //signingCredentials  签名凭证
            //string sign = "q2xiARx$4x3TKqBJ"; //SecurityKey 的长度必须 大于等于 16个字符
            string sign = jwtConfig.signingKey;
            var secret = Encoding.UTF8.GetBytes(sign);
            var key = new SymmetricSecurityKey(secret);
            var signcreds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var jwt = new JwtSecurityToken(issuer: iss, audience: aud, claims: claims, notBefore: nbf, expires: exp, signingCredentials: signcreds);
            var JwtHander = new JwtSecurityTokenHandler();
            var token = JwtHander.WriteToken(jwt);
            return token;
        }

        /// <summary>
        /// 用户注销
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("/logout")]
        [Authorize]
        public Result logout() {
            Debug.WriteLine("登出成功");

            var jwtConfig = configuration.GetSection("JwtConfig").Get<JwtConfig>();

            List<string> authorizations = new List<string>();
            if (!string.IsNullOrEmpty(HttpContext.User.Identity.Name)) {
                if (cache.IsExist(HttpContext.User.Identity.Name)) {
                    authorizations = cache.Get<List<string>>(HttpContext.User.Identity.Name);
                }
                if (!string.IsNullOrEmpty(HttpContext.Request.Headers["Authorization"])) {
                    authorizations.Add(HttpContext.Request.Headers["Authorization"]);
                    //把登出的令牌放进缓存（放进缓存的令牌不能再次登录）
                    cache.Set(HttpContext.User.Identity.Name, authorizations, jwtConfig.expires);
                }
            }
            if (cache.IsExist(HttpContext.Request.Headers["Authorization"])) {
                cache.Remove(HttpContext.Request.Headers["Authorization"]);
            }
            return Result.succ("登出成功");
        }

    }
}
